package com.hncboy.chatgpt.front.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.google.common.collect.Maps;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.hncboy.chatgpt.base.util.WxAesUtil;
import com.hncboy.chatgpt.base.util.LocalJsonUtil;
import com.hncboy.chatgpt.front.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@Slf4j
@Service
public class PayServiceImpl implements PayService {

    //不确定订单相关逻辑，调用支付时再改，暂时只有调用支付的逻辑

    //相关参数最好是放到外部，方便修改

    //商品描述
    String description = "Mi Chat Vip";

    // TODO 支付宝相关参数，后续需要填上
    String aliAppid = "";
    String aliPrivateKey = "";
    String aliPublicKey = "";

    // TODO 微信相关参数，后续需要填上
    String wxAppid = "";
    String wxMchid = "";
    /** 微信商户API私钥路径 */
    public static String wxPrivateKeyPath = "";
    /** 微信商户证书序列号 */
    public static String wxMerchantSerialNumber = "";
    /** 微信商户APIV3密钥 */
    public static String wxApiV3key = "";

    @Override
    public void aliPcPay(Map<String, Object> paramMap) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                aliAppid,
                aliPrivateKey,
                "json",
                "GBK",
                aliPublicKey,
                "RSA2");
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //异步接收地址，仅支持http/https，公网可访问
                request.setNotifyUrl("");
        //同步跳转地址，仅支持http/https
                request.setReturnUrl("");
        /******必传参数******/
                JSONObject bizContent = new JSONObject();
        //商户订单号，商家自定义，保持唯一性
                bizContent.put("out_trade_no", "20210817010101004");
        //支付金额，最小值0.01元
                bizContent.put("total_amount", 0.01);
        //订单标题，不可使用特殊符号
                bizContent.put("subject", description);
        //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
                bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

        /******可选参数******/
        //bizContent.put("time_expire", "2022-08-01 22:00:00");

        //// 商品明细信息，按需传入
        //JSONArray goodsDetail = new JSONArray();
        //JSONObject goods1 = new JSONObject();
        //goods1.put("goods_id", "goodsNo1");
        //goods1.put("goods_name", "子商品1");
        //goods1.put("quantity", 1);
        //goods1.put("price", 0.01);
        //goodsDetail.add(goods1);
        //bizContent.put("goods_detail", goodsDetail);

        //// 扩展信息，按需传入
        //JSONObject extendParams = new JSONObject();
        //extendParams.put("sys_service_provider_id", "2088511833207846");
        //bizContent.put("extend_params", extendParams);

        request.setBizContent(bizContent.toString());
        AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
        if(response.isSuccess()){
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
    }

    @Override
    public String aliPcPayNotify(Map<String, String> paramsMap) throws AlipayApiException {
        boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, aliPublicKey, "GBK", "RSA2"); //调用SDK验证签名
        if(signVerified){
            // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            return "success";
        }else{
            // TODO 验签失败则记录异常日志，并在response中返回failure.
        }
        return "failure";
    }

    @Override
    public void wxNative(Map<String, Object> paramMap, HttpServletResponse response) throws IOException, WriterException {
        //1、获取微信支付短链
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(wxMchid)
                        .privateKeyFromPath(wxPrivateKeyPath)
                        .merchantSerialNumber(wxMerchantSerialNumber)
                        .apiV3Key(wxApiV3key)
                        .build();
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(wxAppid);
        request.setMchid(wxMchid);
        request.setDescription(description);
        // TODO 微信异步通知地址 是否用同一个域名
        request.setNotifyUrl("https://wx/native/notify");
        //我方订单号
        request.setOutTradeNo("out_trade_no_001");
        //附加数据，会通过异步返回接口透传回来
        request.setAttach("");
        // 调用下单方法，得到应答
        PrepayResponse prepayResponse = service.prepay(request);
        // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
        createQrCode(prepayResponse.getCodeUrl(), response);

        //3、获取成功，添加订单记录到数据库，这一步也可以在放在获取支付链接之前，记得添加订单相关状态，比如：下单、下单失败、支付中，支付成功
    }

    @Override
    public Map<String, String> wxNativeNotify(Map<String, String> param) {
        Map<String, String> resp = Maps.newHashMap();
        resp.put("code", "FAIL");
        resp.put("message", "失败");

        String json = LocalJsonUtil.ObjToString(param);
        String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
        String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
        String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
        try {
            String decryptData = new WxAesUtil(wxApiV3key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);

            //TODO 业务校验 流程无误可返回成功
            //resp.put("code", "SUCCESS");
            //resp.put("message", "成功");

        } catch (Exception e) {
            e.printStackTrace();
        }
        return resp;
    }

    /**
     * 创建二维码
     */
    public void createQrCode(String content, HttpServletResponse response) throws WriterException, IOException {
        Map<EncodeHintType, String> hints = Maps.newHashMap();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, 120, 120, hints);
        BufferedImage bufferedImage = new BufferedImage(bitMatrix.getWidth(), bitMatrix.getHeight(), BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < bitMatrix.getWidth(); i++) {
            for (int j = 0; j < bitMatrix.getHeight(); j++) {
                bufferedImage.setRGB(i, j, bitMatrix.get(i, j) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
            }
        }
        ImageIO.write(bufferedImage, "png", response.getOutputStream());
    }

}
